#include <cstring>
#include <cmath>
#include <iostream> //预处理器指令 a PREPROCESSOR directive
#include <vector>
#include <array>

using namespace std; // 使定义可见   make definitions visible

/*
    C++ primer 12.2
    字符串类

*/

class String
{
private:
  char *str;                    // pointer to string
  int len;                      // length of string
  static int num_strings;       // number of objects
  static const int CINLIM = 80; // cin input limit
public:
  // constructors and other methods
  String(const char *s);  // constructor
  String();               // default constructor
  String(const String &); // copy constructor
  ~String();              // destructor

  // 返回被存储的字符串的长度
  int length() const { return len; }

  // overloaded operator methods
  String &operator=(const String &);
  String &operator=(const char *);

  // 表示法访问字符串中各个字符的功能
  char &operator[](int i);
  // 访问常量 str[i] => str.operatro[](i)
  const char &operator[](int i) const;

  // overloaded operator friends
  // 对字符串进行比较
  friend bool operator<(const String &st, const String &st2);
  friend bool operator>(const String &st1, const String &st2);
  friend bool operator==(const String &st, const String &st2);

  // 简单的输入功能
  friend ostream &operator<<(ostream &os, const String &st);
  friend istream &operator>>(istream &is, String &st);

  // static function
  static int HowMany();
};



const int ArSize = 10;
const int MaxLen = 81;

int main()
{
  String sayings[ArSize];
  char temp[MaxLen];               // temporary string storage
  int i;
  for (i = 0; i < ArSize; i++)
  {
    cout << i+1 << ": ";
    cin.get(temp, MaxLen);
    while (cin && cin.get() != '\n')
        continue;
    //在读取空行后，返回的值不为false。然而，对于这些版本来说，如果读取了一个空行，则字符串中第一个字符将是一个空字符。
    if (!cin || temp[0] == '\0') // empty line?
        break;                   // i not incremented(递增)
    else
        sayings[i] = temp;       // overloaded assignment
  }

  int total = i;                   // total # of lines read

  if (total > 0)
  {
    cout << "Here are your sayings:\n";
    for (i = 0; i < total; i++)
      cout << sayings[i] << "\n";

    cout <<"\n";

    // use pointers to keep track of shortest, first strings
    // 使用指针跟踪最短的第一个字符串
    String *shortest = &sayings[0]; // initialize to first object
    //跟踪按字母顺序排在最前面的字符串
    String *first = &sayings[0];

    for (i = 1; i < total; i++)
    {
      if (sayings[i].length() < shortest->length())
        shortest = &sayings[i];
      if (sayings[i] < *first) // compare values 首字母排序
        first = &sayings[i];   // assign address
    }
    cout << "Shortest(最短) saying: " << *shortest << endl;
    cout << "First alphabetically(第一个字母): " << *first << endl;

    srand(time(0));
    int choice = rand() % total; // pick index at random 随机选取索引
    
    // use new to create, initialize new String object
    // 使用new创建、初始化新的String对象
    String *favorite = new String(sayings[choice]);
    //这不是为要存储的字符串分配内存，而是为对象分配内存；也就是说，为保存字符串地址的str指针和len成员分配内存(程序并没有给num_string成员分配内存)

    cout << "My favorite(最喜欢) saying: " << *favorite << endl;
    delete favorite;
  }
  else
    cout << "Not much to say, eh?\n";
  cout << "Bye.\n";
}





// initializing static class member
int String::num_strings = 0;

// static method
int String::HowMany()
{
  return num_strings;
}

// class methods
String::String(const char *s) // construct String from C string
{
  len = std::strlen(s);    // set size
  str = new char[len + 1]; // allot storage
  std::strcpy(str, s);     // initialize pointer
  num_strings++;           // set object count
}

String::String() // default constructor
{
  len = 4;
  str = new char[1];
  str[0] = '\0'; // default string
  num_strings++;
}

String::String(const String &st)
{
  num_strings++;            // handle static member update
  len = st.len;             // same length
  str = new char[len + 1];  // allot space
  std::strcpy(str, st.str); // copy string to new location
}

String::~String() // necessary destructor
{
  --num_strings; // required
  delete[] str;  // required
}

// overloaded operator methods

//assign a String to a String
//赋值运算符 (深度复制)
String& String::operator=(const String& st){
  //函数应当避免将对象赋给自身
  if(this == &st)//object assigned to itself 
    return *this;//all done

  //由于目标对象可能引用了以前分配的数据,释放这些数据
  delete[] str;//free old string
  len = st.len;
  str = new char[len+1];//get space for new string
  std::strcpy(str,st.str);//copythestring
  return *this;//return reference to invoking object 返回调用对象的引用 
}

//assign a C string to a String
String &String::operator=(const char *s)
{
  delete[] str;
  len = std::strlen(s);
  str = new char[len + 1];
  std::strcpy(str, s);
  return *this;
}

// read-write char access for non-const String
char &String::operator[](int i)
{
  return str[i];
}

// read-only char access for const String
const char &String::operator[](int i) const
{
  return str[i];
}

// overloaded operator friends
bool operator<(const String &st1, const String &st2)
{
  return (std::strcmp(st1.str, st2.str) < 0);
}

bool operator>(const String &st1, const String &st2)
{
  return st2 < st1;
}

bool operator==(const String &st1, const String &st2)
{
  return (std::strcmp(st1.str, st2.str) == 0);
}

// simple String output
ostream &operator<<(ostream &os, const String &st)
{
  os << st.str;
  return os;
}

// quick and dirty String input
istream &operator>>(istream &is, String &st)
{
  char temp[String::CINLIM];
  is.get(temp, String::CINLIM);
  if (is)
    st = temp;
  while (is && is.get() != '\n')
    continue;
  return is;
}
